<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        //该文章网址：https://segmentfault.com/a/1190000006150186

        //【1】typeof【无法区分数组】
        //typeof是javascript原生提供的判断数据类型的运算符，它会返回一个表示参数的数据类型的字符串
        //数组被归到了Any other object当中，所以typeof返回的结果应该是Object，并没有办法区分数组，对象，null等原型链上都有Object的数据类型。
        const s = [1, 2, 4];
        console.log(typeof(s)); //object
        //【2】instanceof运算符【可以判断是不是数组】
        // 可以用来判断某个构造函数的prototype属性所指向的對象是否存在于另外一个要检测对象的原型链上。
        // 在使用的时候语法如下：object instanceof constructor
        const a = [];
        const b = {};
        console.log(a instanceof Array); //true
        console.log(a instanceof Object); //true,在数组的原型链上也能找到Object构造函数
        console.log(b instanceof Array); //false
        // 由上面的几行代码可以看出， 使用instanceof运算符可以分辨数组和对象， 可以判断数组是数组。
        //【3】constructor属性【如果手动修改过constructor属性，则无法判断数组】
        // 实例化的数组拥有一个constructor属性， 这个属性指向生成这个数组的方法
        const a1 = [];
        console.log(a1.constructor); //function Array(){ [native code] }
        // 以上的代码说明，数组是有一个叫Array的函数实例化的。
        // 看到这里，你可能会觉得这也是一种靠谱的判断数组的方法，我们可以用以下的方式来判断:
        // 但是，很遗憾的通知你，constructor属性是可以改写的，如果你一不小心作死改了constructor属性的话，
        // 那么使用这种方法就无法判断出数组的真是身份了，写到这里，我不禁想起了无间道的那段经典对白，梁朝伟：“对不起，我是警察。”刘德华：“谁知道呢？”。
        // 【4】Object.prototype.toString【toSring】
        // 每一个继承自Object的对象都拥有toString的方法。
        // 如果一个对象的toString方法没有被重写过的话，那么toString方法将会返回"[object type]"，
        // 【知识点】其中的type代表的是对象的类型，根据type的值，我们就可以判断这个疑似数组的对象到底是不是数组了。

        // 为什么不是直接调用数组，或则字符串自己的的toString方法呢？
        const a2 = ['Hello', 'Howard'];
        const b2 = {
            0: 'Hello',
            1: 'Howard'
        };
        const c2 = 'Hello Howard';
        console.log(a2.toString()); //"Hello,Howard"
        console.log(b2.toString()); //"[object Object]"
        console.log(c2.toString()); //"Hello,Howard"

        //【4-1】除了对象之外，其他的数据类型的toString返回的都是内容的字符创，只有对象的toString方法会返回对象的类型
        const a22 = ['Hello', 'Howard'];
        const b22 = {
            0: 'Hello',
            1: 'Howard'
        };
        const c22 = 'Hello Howard';
        console.log(Object.prototype.toString.call(a22)); //"[object Array]"
        console.log(Object.prototype.toString.call(b22)); //"[object Object]"   
        console.log(Object.prototype.toString.call(c22)); //"[object String]"
        //【4-1】使用apply方法也能达到同样的效果
        const a33 = ['Hello', 'Howard'];
        const b33 = {
            0: 'Hello',
            1: 'Howard'
        };
        const c33 = 'Hello Howard';
        console.log(Object.prototype.toString.apply(a33)); //"[object Array]"
        console.log(Object.prototype.toString.apply(b33)); //"[object Object]"
        console.log(Object.prototype.toString.apply(c33)); //"[object String]"
        //【4-3】总结一下，我们就可以用写一个方法来判断数组是否为数组：
        const isArray = (something) => {
            return Object.prototype.toString.call(something) === '[object Array]';
        }
        const a55 = [];
        const b55 = {};
        isArray(a55); //true
        isArray(b55); //false
        // 但是，如果你非要在创建这个方法之前这么来一下，改变了Object原型链上的toString方法，那我真心帮不了你了...
        //重写了toString方法
        Object.prototype.toString = () => {
                console.log('你吃过了么？');
            }
            //调用String方法
        const a66 = [];
        Object.prototype.toString.call(a66); //弹框问你吃过饭没有
        //【5】用Array对象的isArray方法判断（Array.isArray是ES5标准中增加的方法）
        // 最靠谱的判断数组的方法了
        // 它与instance运算符判断的方法以及Object.prototype.toString法并不相同，一些列的修改并没有影响到判断的结果。

        const a77 = [];
        const b77 = {};
        Array.isArray(a77); //true
        Array.isArray(b77); //false
        // 我试着在调用这个方法之前重写了Object.prototype.toString方法：【不影响】
        Object.prototype.toString = () => {
            console.log('Hello Howard');
        }
        const a88 = [];
        Array.isArray(a88); //true
        // 又试着修改了constructor对象：【不影响】
        const a99 = [];
        const b99 = {};
        a99.constructor = b99.constructor;
        Array.isArray(a99); //true
        // 有读者朋友在评论中提醒我，Array.isArray是ES5标准中增加的方法，部分比较老的浏览器可能会有兼容问题，所以为了增强健壮性，建议还是给Array.isArray方法进行判断，增强兼容性，重新封装的方法如下：
        if (!Array.isArray) {
            Array.isArray = function(arg) {
                return Object.prototype.toString.call(arg) === '[object Array]';
            };
        }
    </script>
</body>

</html>